package com.collins.thread;

import org.apache.commons.io.ThreadUtils;

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class CountDownLatchTest {
    public static final Integer THREAD_COUNT = 10;
    public static final CountDownLatch startBarrier = new CountDownLatch(1);
    public static final CountDownLatch doneBarrier = new CountDownLatch(THREAD_COUNT);
    public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) {
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(new Worker(), "thread-" + Worker.threadCount.getAndIncrement()).start();
        }
        try {
            ThreadUtils.sleep(Duration.ofMillis(1000));
            System.out.println(sdf.format(new Date(System.currentTimeMillis())) + " main thread let pass ...");
            startBarrier.countDown();
            doneBarrier.await();
            System.out.println(sdf.format(new Date(System.currentTimeMillis())) + " worker thread finished");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    static class Worker implements Runnable {

        public static AtomicInteger threadCount = new AtomicInteger(0);
        public static final ReentrantLock lock = new ReentrantLock();

        @Override
        public void run() {
            try {
                // TODO make sure all workers are blocked to start simultaneously
                System.out.println(sdf.format(new Date(System.currentTimeMillis())) + " "
                        + Thread.currentThread().getName() + " comes in, but blocked...");
                startBarrier.await();
                doWork();
                // TODO when main thread unblocked, run this worker thread
                doneBarrier.countDown();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        public void doWork() {
            lock.lock();
            try {
                Thread.sleep(1000);
                System.out.println(sdf.format(new Date(System.currentTimeMillis())) + " "
                        + Thread.currentThread().getName() +
                        " now starts counting down, counts are: " + doneBarrier.getCount());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                lock.unlock();
            }

        }
    }
}
